﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

using System.Xml;
using System.Xml.Xsl;
using System.Diagnostics;

namespace GUI
{
   class TradingClient
   {

      //USE THESE FOR GUI
      List<string> bids = new List<string>();
      List<string>offers = new List<string>();
      List<string> position = new List<string>();



      Socket mdcSocket;
      byte[] receiveBuffer;
      byte[] sendBuffer;
      string [] currentTickers = { "TRAN", "LEGL", "WELL", "ADMN", "HEAL", "UTIL", "SECR", "FIRE" };
      IPAddress groupAddress;
      MulticastOption mcastOption;
      EndPoint localEP;
      EndPoint endPoint;
      IPHostEntry entry;
      //BizDomain domain;
      string Id;
      string order;
      string serv;
      bool login;

      public TradingClient(string trader)
      {
         login = false;
         Id = trader;
         //domain = BizDomain;
         receiveBuffer = new byte[100000];
         sendBuffer = new byte[512];
         groupAddress = IPAddress.Parse("224.5.6.7");
         mcastOption = new MulticastOption(groupAddress);
         //currentTickers = domain.oprocNames;

      }

      public void getInput()
      {
         if (login == false)
         {
            TraderLogin();
            login = true;
         }
         bool check = false;
         bool send = false;
         Console.WriteLine("To enter an order type ORDR");
         Console.Write("Enter Symbol:  ");
         serv = (string)Console.ReadLine();
         if (serv.Length > 4)
            serv = serv.Substring(0, 4);
         serv = serv.ToUpper();
         while (serv != null)
         {
            if (serv.Equals("ORDR"))
            {
               serv = EnterOrder();
               send = true;
            }

            for (int i = 0; i < currentTickers.Length; i++)
            {
               if (serv.Equals(currentTickers[i]))
               {
                  check = true;
                  break;
               }
               
            }
            if (check)
               break;
            if (check == false)
            {
               Console.WriteLine("You entered an invalid symbol!  Please re-enter symbol");
               serv = (string)Console.ReadLine();
               serv = serv.ToUpper();
            }
         }
         if (check && send)
            SendOrder();

         else if (check)
            getQuotes(serv);
         
         check = false;
         send = false;
      }

      public void getFormInput()
      {
          if (login == false)
          {
              TraderLogin();
              login = true;
          }
          bool check = false;
          bool send = false;
          serv = (string) Form2.ins;
          if (serv.Length > 4)
              serv = serv.Substring(0, 4);
          serv = serv.ToUpper();
          while (serv != null)
          {
              if (serv.Equals("ORDR"))
              {
                  serv = EnterOrder();
                  send = true;
              }

              for (int i = 0; i < currentTickers.Length; i++)
              {
                  if (serv.Equals(currentTickers[i]))
                  {
                      check = true;
                      break;
                  }

              }
              if (check)
                  break;
              if (check == false)
              {
                  Console.WriteLine("You entered an invalid symbol!  Please re-enter symbol");
                  serv = (string)Console.ReadLine();
                  serv = serv.ToUpper();
              }
          }
          if (check && send)
              SendOrder();

          else if (check)
              getQuotes(serv);

          check = false;
          send = false;
      }

       
       private void TraderLogin()
      {
         Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
         sendBuffer = Encoding.ASCII.GetBytes(Id);
         mSocket.Connect(mdpEP);
         mSocket.Send(sendBuffer);
         mSocket.Close();
         Console.WriteLine("Sending ID " + Id);
         Console.WriteLine("Login Success!");
         createXSLT();
      }

      private string EnterOrder()
      {
         string ret;
         Console.WriteLine("Trader ID is: " + Id);
         order = Id.ToUpper();
         Console.Write("Enter Service: ");
         ret = Console.ReadLine().ToUpper();
         order += "|" + ret + "|" + "Market" + "|";
         Console.Write("Enter B for Buy; S for Sell: ");
         order += Console.ReadLine().ToUpper() + "|";
         Console.Write("How many contracts? ");
         order += Console.ReadLine() + "|";
         Console.Write("At what price? ");
         order += Console.ReadLine();
         order += "ORDR";
         sendBuffer = Encoding.ASCII.GetBytes(order);         
         return ret;
      }

      private void SendOrder()
      {
         Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
         mSocket.Connect(mdpEP);
         mSocket.Send(sendBuffer);
         mSocket.Close();
         Console.WriteLine("Sending Order " + order);
         Console.WriteLine("Order Input Success!");
         getQuotes(serv);
      }

      private void getQuotes(string service)
      {
         Socket mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         IPEndPoint mdpEP = new IPEndPoint(IPAddress.Loopback, 20000);
         mSocket.Connect(mdpEP);

         sendBuffer = Encoding.ASCII.GetBytes(service);
         mSocket.Send(sendBuffer);
         Console.WriteLine("getting service: " + service);
         Console.WriteLine("");
         mSocket.Close();
         receiveMultiCast();
         
      }

      public void receiveMultiCast()
      {        
         int check = 1;
         bool off=false;
         while (check > 0)
         {
            int bytesReceived = mdcSocket.ReceiveFrom(receiveBuffer, ref endPoint);
            check = bytesReceived;
            IPEndPoint mdpEndPoint = (IPEndPoint)endPoint;
            int index = 0;
            string mktPrice = Encoding.ASCII.GetString(receiveBuffer, index, bytesReceived);

            if (mktPrice.Contains("~"))
            {
               check = mktPrice.Length - 5;
               off = true;
            }
            else
               check = mktPrice.Length - 4;

            if (mktPrice.Contains("<?xml"))
            {
                mktPrice = mktPrice.Remove(mktPrice.Length - 1);
                displayXML(mktPrice);
            }
            else //when not xml
            {
                mktPrice = mktPrice.Remove(check);
                ServiceOrder s = ConstructOrder(mktPrice);
                Order o = (Order)s;
                //Console.WriteLine(o.ToString());
                if (o.ToString().Contains(Id))
                    position.Add(o.ToString());
                if (o.ToString().Contains(" B "))
                    bids.Add(o.ToString());
                if (o.ToString().Contains(" S "))
                    offers.Add(o.ToString());

                if (off)
                    check = 0;
            }

         }


         
         
         
         
         
         //This is how you extract the strings to put in GUI
         Console.WriteLine("Bids");
         //have to reverse the order so its highest price first
         bids.Reverse();
         foreach(string s in bids)
            Console.WriteLine(s);

         Console.WriteLine();

         //Offers already in correct order
         Console.WriteLine("Offers");
         foreach(string s in offers)
            Console.WriteLine(s);

         Console.WriteLine();

         //the traders current position
         Console.WriteLine("Current Position");
         foreach (string trade in position)
            Console.WriteLine(trade);


         //start a new thread for this
         offers.Clear();
         bids.Clear();
         Thread input = new Thread(getFormInput);
         input.Start();
      }

      //public void receiveMultiCast()
      //{         
      //   EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
      //   mdcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
      //   mdcSocket.Bind(localEP);
      //   mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);
      //   int check = 1;
      //   int tracker = 0;
      //   bool full = false;
      //   string[] orderInfo = new string[6];       
      //   while (check > 0)
      //   {
      //      int bytesReceived = mdcSocket.ReceiveFrom(receiveBuffer, ref endPoint);
      //      check = bytesReceived;
      //      IPEndPoint mdpEndPoint = (IPEndPoint)endPoint;
      //      int index=0;          
      //      string mktPrice = Encoding.ASCII.GetString(receiveBuffer, index, bytesReceived);          
      //      if (mktPrice.Contains("ORDR"))
      //      {
      //         check = mktPrice.Length - 4;
      //         mktPrice = mktPrice.Remove(check);
      //         orderInfo[tracker] = mktPrice;
      //         ServiceOrder s = ConstructOrder(orderInfo);
      //         Order o = (Order)s;
      //         Console.WriteLine(o.ToString());
      //         //send order to orderbook
      //         //domain.SubmitOrder(s.Instrument, s);
      //         check = 0;
      //      }
      //      if (tracker == 5)
      //      {
      //         orderInfo[tracker] = mktPrice;
      //         index += mktPrice.Length;
      //         ServiceOrder s = ConstructOrder(orderInfo);
      //         Order o = (Order)s;
      //         Console.WriteLine(o.ToString());
      //         //send order to orderbook
      //         //domain.SubmitOrder(s.Instrument, s);
      //         full = true;
      //      }
      //      else
      //      {
      //         orderInfo[tracker] = mktPrice;
      //         index += mktPrice.Length;
      //      }

      //      tracker++;


      //      if (full == true)
      //      {
      //         tracker = 0;
      //         full = false;
      //      }

      //   }
      //   Console.WriteLine();
      //   //Console.WriteLine("Market Data Producer IP Address {0} Port {1} ", mdpEndPoint.Address.ToString(), mdpEndPoint.Port);
      //   //mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, mcastOption);
      //   Console.WriteLine("Closing multicast socket");
      //   orderInfo = null;
      //   mdcSocket.Close();
      //   //start a new thread for this
      //   Thread input = new Thread(getInput);
      //   input.Start();	
      //}

      private ServiceOrder BuildOrder(string[] mktOrder)
      {
         string id = mktOrder[0];
         string inst = mktOrder[1];
         string type = mktOrder[2];
         string bs = mktOrder[3];
         int quant = Int32.Parse(mktOrder[4]);
         double price = Double.Parse(mktOrder[5]);
         
         ServiceOrder serv = new ServiceOrder(id, inst, type, bs, price, quant);
         return serv;
      }

      private ServiceOrder ConstructOrder(string mktOrder)
      {
         string[] orderString = new string[6];
         int mark = 0;
         string part = "";
         for (int i = 0; i < mktOrder.Length; i++)
         {
            
            if (!mktOrder.ElementAt(i).Equals('|'))
            {
               part += mktOrder.ElementAt(i) ;
            }
            else 
            {
               orderString[mark] = part;
               mark++;
               part = "";
            }
            
         }

         orderString[mark] = part;
         ServiceOrder serv = BuildOrder(orderString);
         return serv;
      }

      public void Start()
      {
         Console.WriteLine("Market-Data Consumer Service Started - (Using MultiCast)");	
         byte[] receiveBuffer = new byte[512];
         entry = Dns.GetHostByName(Dns.GetHostName());
		   localEP = new IPEndPoint(entry.AddressList[0],30002);
		   
         //test code to change up what services we are generating
         Console.WriteLine("Please enter the service you wish to see");
         Console.WriteLine("Available Services are:");
         for (int i = 0; i < currentTickers.Length; i++)
            Console.WriteLine(currentTickers[i]);

         endPoint = new IPEndPoint(IPAddress.Any, 0);
         mdcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
         mdcSocket.Bind(localEP);
         mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);

         getFormInput();

      }

		public static void DisableMulticastLoopBack(Socket sockInstance)
		{
			sockInstance.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.MulticastLoopback,0);
		}

        private static void createXSLT()
        {
            string xsltMsg = "<?xml version = \"1.0\" encoding=\"ISO-8859-1\" ?>";

            xsltMsg += "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">";
            xsltMsg += "<xsl:output method=\"html\" />";
            xsltMsg += "<xsl:template match=\"/\">";
            xsltMsg += "<html><body><h2>Trade Printout</h2>";
            xsltMsg += "<table border=\"1\"><tr align=\"center\"><th>Service</th><th bgcolor=\"red\" width=\"50 px\">Bid</th><th bgcolor=\"green\" width=\"50 px\">Offer</th><th>Quantity</th><th>Price</th></tr>";
            xsltMsg += "<xsl:for-each select=\"TQ/Trade\">";
            xsltMsg += "<tr align=\"center\"><td><xsl:value-of select=\"Serv\"/></td><td bgcolor=\"red\"><xsl:value-of select=\"bID\"/></td><td bgcolor=\"green\"><xsl:value-of select=\"sID\"/></td><td><xsl:value-of select=\"quant\"/></td><td><xsl:value-of select=\"pr\"/></td></tr>";
            xsltMsg += "</xsl:for-each></table></body></html></xsl:template></xsl:stylesheet>";

            System.IO.File.WriteAllText(@"C:\\Temp\\A1Exchange.xslt", xsltMsg);
        }

        private static void displayXML(string xmlMsg)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlMsg);

            doc.Save("C:\\Temp\\A1Exchange.xml");

            XslTransform tranXml = new XslTransform();
            tranXml.Load("C:\\Temp\\A1Exchange.xslt");

            tranXml.Transform("C:\\Temp\\A1Exchange.xml", "C:\\Temp\\A1Exchange.html");
            Process.Start("C:\\Temp\\A1Exchange.html");
        }

   }
}
